package com.ape.mapsa.common;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.activiti.engine.task.Task;
import org.apache.log4j.Logger;
import org.primefaces.context.RequestContext;
import org.springframework.dao.DataIntegrityViolationException;

import com.ape.mapsa.bpm.service.IBPMService;
import com.ape.mapsa.bpm.service.ProductionHelper;
import com.ape.mapsa.common.constants.EstadoProduccion;
import com.ape.mapsa.produccion.constants.TipoMaquina;
import com.ape.mapsa.produccion.model.Formula;
import com.ape.mapsa.produccion.model.Item;
import com.ape.mapsa.produccion.model.Maquina;
import com.ape.mapsa.produccion.model.OpComment;
import com.ape.mapsa.produccion.model.OrdenProduccion;
import com.ape.mapsa.produccion.service.IProduccionService;
import com.ape.mapsa.service.IUserService;

@ManagedBean(name = "apprMB")
@ViewScoped
public class AprobacionBean implements Serializable {

	private static final long serialVersionUID = -1977508801914942345L;

	private static final Logger log = Logger.getLogger(AprobacionBean.class);

	@ManagedProperty("#{produccionService}")
	private IProduccionService prodService;

	@ManagedProperty(value = "#{UserService}")
	IUserService userService;

	@ManagedProperty(value = "#{BPMService}")
	IBPMService bpmService;

	@ManagedProperty(value = "#{homeMenuMB}")
	private UserHomeMenuBean homeBean;

	@ManagedProperty(value = "#{prodSpecMB}")
	private ProdSpecsBean prodSpecs;

	@ManagedProperty(value = "#{formulasMB}")
	private FormulasBean formulaBean;

	@ManagedProperty(value = "#{ordenProdMB}")
	private OrdenProdBean ordenProd;

	private String taskId;
	private String executionId;
	private String taskDefKey;
	private String taskDescription;

	private String itemId;
	private Item item;

	private String comment;

	@PostConstruct
	public void getProdHome() {
		log.info("Initializing aprobation bean");
		initilize();
	}

	protected void initilize() {
		FacesContext fc = FacesContext.getCurrentInstance();
		Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
		executionId = params.get("executionId");
		taskDefKey = params.get("taskDefKey");
		setTaskId(params.get("taskId"));
		taskDescription = params.get("taskDescription");

		Task task = bpmService.getTaskById(executionId);
		Object ordenProdIdO = task.getProcessVariables().get("orden_prod_id");
		if (ordenProdIdO != null) {
			OrdenProduccion opById = prodService.getOpById(Long.parseLong(ordenProdIdO.toString()));
			prodSpecs.setOrdenProd(opById);
			ordenProd.setSelectedOp(opById);
		}

		String itemCode = null;
		if (taskDefKey.equals("aprobacionItemNuevoProd")) {
			Object approvedItemCode = task.getProcessVariables().get("new_art_code");
			log.debug("Approved item code: " + approvedItemCode.toString());
			itemCode = approvedItemCode.toString();
			if (itemCode != null) {
				item = prodService.getItemByCode(itemCode);
			}
		} else if (taskDefKey.equals("approveNewItemAdmin")) {
			Object itemCodeObj = task.getProcessVariables().get("item_code");
			log.debug("Item code: " + itemCodeObj);
			itemCode = itemCodeObj.toString();
			if (itemCode != null) {
				item = prodService.getItemByCode(itemCode);
			}
		} else {
			if (ordenProdIdO != null) {
				formulaBean.setSelectedFormula(null);
				formulaBean.setSelectedFormula(ordenProd.getSelectedOp().getFormula());
				log.debug("Selected Fromula: " + formulaBean.getSelectedFormula());
				if (formulaBean.getSelectedFormula() != null && formulaBean.getSelectedFormula().getId() != null) {
					log.debug("prod order has no formula, getting formula...");
					formulaBean.getSelectedFormula().setFormulaMps(prodService.getMpForFormula(formulaBean.getSelectedFormula()));
				} else {
					ordenProd.getSelectedOp().setFormula(new Formula());
					formulaBean.setSelectedFormula(ordenProd.getSelectedOp().getFormula());
					log.debug("prod order has no formula");
				}
			}
			if (ordenProdIdO != null) {
				if (prodSpecs.getOrdenProd().getExtrusion().getMaquina() == null) {
					log.debug("Extrusion vino sin maquina");
					Maquina maq = new Maquina();
					prodSpecs.getOrdenProd().getExtrusion().setMaquina(maq);
				}

				if (prodSpecs.getOrdenProd().getImpresions().getMaquina() == null && prodSpecs.getOrdenProd().getItem().getImpresion()) {
					log.debug("Impresion de orden de produccion vino sin maquina.");
					Maquina maq = new Maquina();
					prodSpecs.getOrdenProd().getImpresions().setMaquina(maq);
				}

				if (prodSpecs.getOrdenProd().getConfeccions().getMaquina() == null) {
					log.debug("Confeccion de orden de produccion vino sin maquina.");
					Maquina maq = new Maquina();
					prodSpecs.getOrdenProd().getConfeccions().setMaquina(maq);
				}

			}
		}
	}

	public void approveProdSpecs(ActionEvent event) {
		// Date validation
		boolean validationFaild = false;
		Date extFi = prodSpecs.getOrdenProd().getExtrusion().getFechaInicio();
		Date extFf = prodSpecs.getOrdenProd().getExtrusion().getFechaFin();
		Date confFi = prodSpecs.getOrdenProd().getConfeccions().getFechaInicio();
		Date confFf = prodSpecs.getOrdenProd().getConfeccions().getFechaFin();
		Date impFi = null;
		Date impFf = null;
		if (prodSpecs.getOrdenProd().getImpresions() != null) {
			impFi = prodSpecs.getOrdenProd().getImpresions().getFechaInicio();
			impFf = prodSpecs.getOrdenProd().getImpresions().getFechaFin();
		}

		if (extFf != null && extFi.getTime() > extFf.getTime()) {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Intervalo de fecha",
					"La fecha de inicio de extrusion no puede ser posterior a la fecha final");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			validationFaild = true;
		}

		if (confFf != null && confFi.getTime() > confFf.getTime()) {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Intervalo de fecha",
					"La fecha de inicio de confección no puede ser posterior a la fecha final");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			validationFaild = true;
		}

		if (impFf != null && impFi != null && impFi.getTime() > impFf.getTime()) {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Intervalo de fecha",
					"La fecha de inicio de impresión no puede ser posterior a la fecha final");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			RequestContext.getCurrentInstance().scrollTo(":inboxMenuForm");
			validationFaild = true;
		}
		// VALIDACION DE MAQUINA

		// TODO: esto para todas las maquinas
		if (prodSpecs.getOrdenProd().getConfeccions().getMaquina() != null) {
			Integer confMaqTipo = prodSpecs.getOrdenProd().getConfeccions().getMaquina().getMaqTipo();
			if (confMaqTipo != TipoMaquina.CONFECCIONADORA.getValor()) {
				FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina confeccionadora");
				FacesContext.getCurrentInstance().addMessage(null, msg);
				validationFaild = true;
			}
		} else {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina confeccionadora");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			validationFaild = true;
		}

		if (prodSpecs.getOrdenProd().getExtrusion().getMaquina() != null) {
			Integer extMaqTipo = prodSpecs.getOrdenProd().getExtrusion().getMaquina().getMaqTipo();
			if (extMaqTipo != TipoMaquina.EXTRUSORA.getValor()) {
				FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina extrusora");
				FacesContext.getCurrentInstance().addMessage(null, msg);
				validationFaild = true;
			}
		} else {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina extrusora");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			validationFaild = true;
		}

		Integer impMaqTipo = null;
		if (prodSpecs.getOrdenProd().getItem().getImpresion()) {
			if (prodSpecs.getOrdenProd().getImpresions().getMaquina() != null) {
				impMaqTipo = prodSpecs.getOrdenProd().getImpresions().getMaquina().getMaqTipo();
				if (prodSpecs.getOrdenProd().getItem().getImpresion() && impMaqTipo != TipoMaquina.IMPRESORA.getValor()) {
					FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina impresora");
					FacesContext.getCurrentInstance().addMessage(null, msg);
					validationFaild = true;
				}
			} else {
				FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Maquina", "Verifique la maquina impresora");
				FacesContext.getCurrentInstance().addMessage(null, msg);
				validationFaild = true;
			}
		}

		if (validationFaild) {
			RequestContext.getCurrentInstance().addCallbackParam("isValid", false);
			RequestContext.getCurrentInstance().scrollTo("approveForm:itemDataGrwol");
			return;
		}

		log.info("Apprve Product specs: " + itemId);
		Long oldProdState = prodSpecs.getOrdenProd().getEstadoProduccion().getId();
		try {
			if (taskDefKey.equals("authorize_prod_spec")) {
				prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.ESP_APROBADAS.getId()));
			} else if (taskDefKey.equals("authordizeQuality")) {
				prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.CALIDAD_APROBADA.getId()));
			}
			prodService.updateOp(prodSpecs.getOrdenProd());
			for (Task task : homeBean.getTasks()) {
				if (task.getExecutionId().equals(executionId)) {
					Map<String, Object> values = new HashMap<String, Object>();
					values.put("approved", "true");
					bpmService.completeTask(task.getId(), values);
					homeBean.initilizeMenu();
					FacesContext.getCurrentInstance().getExternalContext().redirect("notificaciones.xhtml");
				}
			}

		} catch (Exception e) {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error en la aprobacion", prodSpecs.getOrdenProd().getId().toString());
			FacesContext.getCurrentInstance().addMessage(null, msg);
			prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(oldProdState));
			prodService.updateOp(prodSpecs.getOrdenProd());
			log.error(e);
		}
	}

	public void approveItem(ActionEvent event) {
		log.info("Apprve Item: " + itemId);
		String oldCode = "";
		try {
			oldCode = item.getCodigo();
			log.debug("Old code: " + oldCode);
			item.setCodigo(itemId);
			item.setItemState(ProductionHelper.APPROVED_BYADMIN_ITEM);
			log.debug("saving item and op: " + item);
			prodSpecs.getOrdenProd().setItem(item);
			prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.ARTICULO_APROBADO_ADMIN.getId()));
			log.debug("saving op: " + prodSpecs.getOrdenProd());
			prodService.updateOp(prodSpecs.getOrdenProd());
			for (Task task : homeBean.getTasks()) {
				if (task.getExecutionId().equals(executionId)) {
					Map<String, Object> values = new HashMap<String, Object>();
					values.put("approved", "true");
					values.put("new_art_code", itemId);
					log.debug("Completing task " + task.getTaskDefinitionKey() + " : " + task.getDescription());
					bpmService.completeTask(task.getId(), values);
					log.debug("Task completed");
					homeBean.initilizeMenu();
					FacesContext.getCurrentInstance().getExternalContext().redirect("notificaciones.xhtml");
				}
			}

		} catch (Exception e) {
			if (e instanceof DataIntegrityViolationException) {
				// VALIDACION
				item.setCodigo(oldCode);
				item.setItemState(ProductionHelper.NEW_ITEM);
				FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Coidgo Duplicado", itemId);
				FacesContext.getCurrentInstance().addMessage(null, msg);
				return;
			} else {
				item.setCodigo(oldCode);
				item.setItemState(ProductionHelper.NEW_ITEM);
				prodService.updateItem(item);
				e.printStackTrace();
			}
		}
	}

	public void approveItemProd(ActionEvent event) {
		try {
			log.debug("Approving article with production user");
			item.setItemState(ProductionHelper.ACTIVE_ITEM);
			log.debug("Updating item: " + item);
			prodService.updateItem(item);
			prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.ITEM_NUEVO_APROBADO.getId()));
			log.debug("Updating OP: " + prodSpecs.getOrdenProd());
			prodService.updateOp(prodSpecs.getOrdenProd());
			for (Task task : homeBean.getTasks()) {
				if (task.getExecutionId().equals(executionId)) {
					Map<String, Object> values = new HashMap<String, Object>();
					values.put("approved", "true");
					log.debug("Completing task " + task.getTaskDefinitionKey() + " : " + task.getDescription());
					bpmService.completeTask(task.getId(), values);
					log.debug("Task completed");
					homeBean.initilizeMenu();
					FacesContext.getCurrentInstance().getExternalContext().redirect("notificaciones.xhtml");
				}
			}

		} catch (Exception e) {
			item.setItemState(ProductionHelper.APPROVED_BYADMIN_ITEM);
			prodService.updateItem(item);
			log.error(e);
		}
	}

	// TODO: HACER ESTE TASK REJECT MAS GENERAL NO SOLO DE ITEM
	public void rejectTask(ActionEvent event) {
		log.info("Reject Task " + taskId);
		String userEmail = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
		try {
			if (taskDefKey.equals("authorize_prod_spec")) {
				prodSpecs.getOrdenProd().setEstadoProduccion(
						prodService.getEstadoProduccionById(EstadoProduccion.ESPECIFICACIONES_RECHAZADAS.getId()));
			} else if (taskDefKey.equals("approveNewItem")) {
				item.setItemState(ProductionHelper.REJECTED_ITEM);
				prodService.updateItem(item);
				prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.ITEM_NUEVO_RECHAZADO.getId()));
			} else if (taskDefKey.equals("authordizeQuality")) {
				prodSpecs.getOrdenProd().setEstadoProduccion(prodService.getEstadoProduccionById(EstadoProduccion.CALIDAD_RECHAZADA.getId()));
			}
			prodService.updateOp(prodSpecs.getOrdenProd());
			if (!comment.isEmpty()) {
				OpComment commentToSave = new OpComment();
				commentToSave.setAuthor(userEmail);
				commentToSave.setOrdenProduccionBean(prodSpecs.getOrdenProd());
				commentToSave.setType(1);
				commentToSave.setComment(comment);
				prodService.saveComment(commentToSave);
			}
			for (Task task : homeBean.getTasks()) {
				if (task.getExecutionId().equals(executionId)) {
					Map<String, Object> values = new HashMap<String, Object>();
					values.put("approved", "false");
					values.put("rejectionComments", comment);
					values.put("rejectedBy", userEmail);
					bpmService.completeTask(task.getId(), values);
					log.info("Item rechazado exitosamente");
					homeBean.initilizeMenu();
					FacesContext.getCurrentInstance().getExternalContext().redirect("notificaciones.xhtml");
				}
			}

		} catch (Exception e) {
			log.error(e);
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error en el sistema", "comuniquese con el administrador");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return;
		}
	}

	public IProduccionService getProdService() {
		return prodService;
	}

	public void setProdService(IProduccionService prodService) {
		this.prodService = prodService;
	}

	public IUserService getUserService() {
		return userService;
	}

	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	public IBPMService getBpmService() {
		return bpmService;
	}

	public void setBpmService(IBPMService bpmService) {
		this.bpmService = bpmService;
	}

	public String getExecutionId() {
		return executionId;
	}

	public void setExecutionId(String executionId) {
		this.executionId = executionId;
	}

	public String getTaskDefKey() {
		return taskDefKey;
	}

	public void setTaskDefKey(String taskDefKey) {
		this.taskDefKey = taskDefKey;
	}

	public Item getItem() {
		return item;
	}

	public void setItem(Item item) {
		this.item = item;
	}

	public String getItemId() {
		return itemId;
	}

	public void setItemId(String itemId) {
		this.itemId = itemId;
	}

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

	public UserHomeMenuBean getHomeBean() {
		return homeBean;
	}

	public void setHomeBean(UserHomeMenuBean homeBean) {
		this.homeBean = homeBean;
	}

	public ProdSpecsBean getProdSpecs() {
		return prodSpecs;
	}

	public void setProdSpecs(ProdSpecsBean prodSpecs) {
		this.prodSpecs = prodSpecs;
	}

	public String getTaskDescription() {
		return taskDescription;
	}

	public void setTaskDescription(String taskDescription) {
		this.taskDescription = taskDescription;
	}

	public OrdenProdBean getOrdenProd() {
		return ordenProd;
	}

	public void setOrdenProd(OrdenProdBean ordenProd) {
		this.ordenProd = ordenProd;
	}

	public FormulasBean getFormulaBean() {
		return formulaBean;
	}

	public void setFormulaBean(FormulasBean formulaBean) {
		this.formulaBean = formulaBean;
	}

}
